package com.easylinkin.sm.service.impl;

import com.easylinkin.sm.constant.DepartmentConstant;
import com.easylinkin.sm.entity.Department;
import com.easylinkin.sm.mapper.DepartmentMapper;
import com.easylinkin.sm.repository.DepartmentRepository;
import com.easylinkin.sm.service.DepartmentService;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.morn.boot.data.DisplayableServiceSupport;
import site.morn.boot.jpa.SpecificationFunction;
import site.morn.boot.rest.RestPage;
import site.morn.core.CriteriaMap;
import site.morn.exception.ApplicationMessages;
import site.morn.framework.context.AccountContext;
import site.morn.framework.entity.BaseDepartment;
import site.morn.framework.entity.BaseDepartment.Fields;
import site.morn.log.OperateArguments;
import site.morn.rest.RestModel;
import site.morn.rest.RestPageable;

/**
 * 机构管理
 *
 * @author wujie
 * @since 0.1.1,  2019/08/19
 */
@Slf4j
@Service
@Transactional
public class DepartmentServiceImpl extends
    DisplayableServiceSupport<Department, Long, DepartmentRepository> implements DepartmentService {

  @Autowired
  private DepartmentMapper departmentMapper;

  @Override
  public <S extends Department> S add(RestModel<S> restModel) {
    S model = restModel.getModel();
    model.setDisplay(true);
    Long parentId = model.getParentId();
    if (Objects.isNull(parentId)) {
      throw ApplicationMessages.translateException(DepartmentConstant.Error.PARENT_ID_NOT_NULL)
          .exception();
    }
    //校验name
    this.nameValidate(model.getName(), parentId);
    // 自动生成id、searchCode
    Optional<Department> optional = this.repository().findById(parentId);
    if (!optional.isPresent()) {
      throw ApplicationMessages.translateException(DepartmentConstant.Error.PARENT_DEPT_NOT_EXIST)
          .exception();
    }
    Department department = optional.get();
    S add = super.add(restModel);
    OperateArguments.add(model.getName());
    String searchCode = department.getSearchCode() + add.getId() + "!";
    add.setSearchCode(searchCode);
    return add;
  }

  @Override
  public <S extends Department> S update(RestModel<S> restModel) {
    S model = restModel.getModel();
    this.nameValidate(model.getName(), model.getParentId(), model.getId());
    S update = super.update(restModel);
    OperateArguments.add(model.getName());
    return update;
  }

  @Override
  public void batchDelete(List<String> searchCodes) {
    searchCodes.forEach(x -> this.repository().patchHide(x + "%"));
  }

  @Override
  public Page<Department> getDeptPage(
      RestPage<Department> restPage) {
    Department model = restPage.getModel();
    model.setDisplay(true);
    RestPageable pageable = restPage.getPageable();
    com.baomidou.mybatisplus.extension.plugins.pagination.Page page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page(
        pageable.getPage() + 1L, pageable.getSize());
    BaseDepartment baseDepartment = AccountContext.activeDepartment();
    List<Department> list;
    if (StringUtils.isEmpty(model.getSearchCode()) || !model.getSearchCode()
        .startsWith(baseDepartment.getSearchCode())) {
      model.setSearchCode(baseDepartment.getSearchCode());
    }
    list = departmentMapper.getDeptPage(model, page);
    page.setRecords(list);

    PageRequest pageRequest = restPage.generatePageRequest();

    return new PageImpl(list, pageRequest, page.getTotal());
  }

  @Override
  public List<Department> getDeptAll(RestModel<Department> restModel) {
    Department model = restModel.getModel();
    model.setDisplay(true);
    BaseDepartment baseDepartment = AccountContext.activeDepartment();

    List<Department> list = new ArrayList<>();
    if (Objects.isNull(model.getParentId())) {
      Department department = departmentMapper.findOne(baseDepartment.getId());
      list.add(department);
    } else {
      list = departmentMapper.getDeptPage(model);
    }
    return list;
  }

  @Override
  protected SpecificationFunction searchSpecificationFunction(Department model,
      CriteriaMap attach) {
    return (reference, restrain, predicate) -> restrain.appendAnd(predicate.startWith(Fields.searchCode))
        .appendAnd(predicate.notEqual(Fields.searchCode))
        .appendAnd(predicate.contain(Fields.name))
        .appendAnd(predicate.eq(Department.Fields.display), predicate.eq(Fields.parentId));
  }

  /**
   * 新增：名称同级校验
   */
  private void nameValidate(String name, Long parentId) {
    Long count = this.repository().countByNameAndParentIdAndDisplay(name, parentId, true);
    if (count > 0) {
      throw ApplicationMessages.translateException(DepartmentConstant.Error.DEPT_NAME_REPEAT)
          .exception();
    }
  }

  /**
   * 修改：名称同级校验
   */
  private void nameValidate(String name, Long parentId, Long id) {
    Long count = this.repository()
        .countByNameAndParentIdAndIdNotAndDisplay(name, parentId, id, true);
    if (count > 0) {
      throw ApplicationMessages.translateException(DepartmentConstant.Error.DEPT_NAME_REPEAT)
          .exception();
    }
  }

}


